home *** CD-ROM | disk | FTP | other *** search
/ Internet Info 1993 / Internet Info CD-ROM (Walnut Creek) (1993).iso / networking / cisco / tcpf.c < prev    next >
C/C++ Source or Header  |  1992-08-07  |  12KB  |  419 lines

  1. /*
  2.  * tcpf.c -- TCP to stdio filter
  3.  *
  4.  *   July 1987, Kirk Lougheed
  5.  *
  6.  *   Copyright (c) 1987 by cisco Systems, Inc.
  7.  *
  8.  *   This program is designed to read and write from standard input and
  9.  *   output to a raw TCP socket.  The specific application is sending data
  10.  *   to printers attached to a terminal server's serial or parallel ports.
  11.  *  
  12.  *   This program may be used in a shell script.  The following example is
  13.  *   of a "print" command that sends text to a PostScript printer.
  14.  *
  15.  *  /usr/local/bin/lptops -2 -o -ntr $* | /usr/local/bin/tcpf -e chaff 4008 &
  16.  *
  17.  *   To use it to stuff a file at a gateway called wilma, for instance, use
  18.  *   the command line:
  19.  *   
  20.  *      tcpf -t wilma 23 <doit
  21.  *   
  22.  *   where the file doit contains, for instance:
  23.  *   
  24.  *      foo^M
  25.  *      ena
  26.  *      foobar^M
  27.  *      ping
  28.  *      ip^Mnit^M100^M^M^M^M
  29.  *      disa
  30.  *      exit
  31.  *   
  32.  *   This script will log onto wilma, get into enable mode, then send 100 pings
  33.  *   aimed at nit.  Output from wilma will be delivered back to the initiator.
  34.  *   
  35.  *   Note that the ^M's in this message must be actual control-M's in the
  36.  *   file -- most of the parsing uses 015 as the line terminator, and tcpf
  37.  *   does not deal with NVT or CRLF issues.  It turns out that our exec
  38.  *   uses 015 or 012 as a line terminator, so the some of the commands can
  39.  *   have normal newlines at the end.
  40.  */
  41.  
  42. #include <sys/types.h>
  43. #include <stdio.h>
  44. #include <sys/socket.h>
  45. #include <netdb.h>
  46. #include <netinet/in.h>
  47. #include <arpa/inet.h>
  48. #include <signal.h>
  49. #include <setjmp.h>
  50. #include <sys/time.h>
  51. #include <sys/ioctl.h>
  52. #include <errno.h>
  53.  
  54. #define TRUE 1
  55. #define FALSE 0
  56.  
  57. #define LF 0xA
  58. #define CR 0xD
  59.  
  60. /* Accommodate worst case for stupid printers (-r switch) */
  61. #define TCPFBUFSIZ (BUFSIZ * 2)
  62.  
  63. int debug;                      /* -d switch */
  64. int eofmode;                    /* -e switch */
  65. int timeoutmode;                /* -t switch */
  66. int crlfmode;                   /* -r switch */
  67. int timeoutlen;
  68. int openwait;                   /* -w switch */
  69. int openwaitlen;
  70.  
  71. struct sockaddr_in sock;
  72. jmp_buf terminate;
  73. unsigned char netbuffer[BUFSIZ];
  74. unsigned char netoutbuffer[TCPFBUFSIZ];
  75. unsigned char ttybuffer[BUFSIZ];
  76. int bytesread, byteswrote;
  77.  
  78. void crashed();
  79. void transfer();
  80.  
  81. /*
  82.  * main
  83.  * Parse command line and set up transfer.
  84.  *
  85.  *     tcpf [-d -e -r -t -w] host port
  86.  *
  87.  *      -d              Enable debugging output.
  88.  *      -e              Send CTRL/D over TCP side when EOF received on stdin.
  89.  *                        This makes PostScript printers very happy.
  90.  *      -r              Send a <CR><LF> pair to stream for every <LF> given
  91.  *                      in stdin.
  92.  *      -t[time]        Timeout in seconds.  Default is 5 min.
  93.  *      -w[time]        Wait for Time while opening connection too.
  94.  *      host            Host name, either symbolic or dotted decimal.
  95.  *      port            Decimal TCP port number.  No defaults.
  96.  */
  97.  
  98. main(argc, argv)
  99.     int argc;
  100.     char *argv[];
  101. {
  102.     char *hostname;
  103.     unsigned short port;
  104.     int conn;
  105.  
  106.     debug = FALSE;
  107.     eofmode = FALSE;
  108.     timeoutmode = FALSE;
  109.     crlfmode = FALSE;
  110.     argc--; argv++;
  111.     while (argc > 1 && (argv[0][0] == '-')) {
  112.         switch (argv[0][1]) {
  113.             case 'd':
  114.             case 'D':
  115.                 debug = TRUE;
  116.                 break;
  117.             case 'e':
  118.             case 'E':
  119.                 eofmode = TRUE;
  120.                 break;
  121.             case 'r':
  122.             case 'R':
  123.                 crlfmode = TRUE;
  124.                 break;
  125.             case 't':
  126.             case 'T':
  127.                 timeoutmode = TRUE;
  128.                 timeoutlen = atoi(&argv[0][2]);
  129.                 if (timeoutlen == 0)
  130.                   timeoutlen = 300;
  131.                 break;
  132.             case 'w':
  133.             case 'W':
  134.                 openwait = TRUE;
  135.                 openwaitlen = atoi(&argv[0][2]);
  136.                 if (openwaitlen <= 0)
  137.                     openwaitlen = 300;
  138.                 break;
  139.             default:
  140.                 fprintf(stderr, "Usage: tcpf [-d -e -r -t[sec] -w[sec]] host port\n");
  141.                 exit(1);
  142.         }
  143.         argc--; argv++;
  144.     }
  145.     if (argc != 2) {
  146.         fprintf(stderr, "Usage: tcpf [-d -e -t[sec] -w[sec]] host port\n");
  147.         exit(1);
  148.     }
  149.     hostname = argv[0];
  150.     port = atoi(argv[1]);
  151.     if (!setup_socket(&sock, hostname, port))
  152.         exit(1);
  153.     if (debug) {
  154.         fprintf(stderr, "Connecting to \"%s, %d\"... ",
  155.             inet_ntoa(sock.sin_addr), ntohs(sock.sin_port));
  156.         fflush(stderr);
  157.     }
  158.     conn = setup_connection(&sock);
  159.     if (conn < 0)
  160.         exit(1);
  161.     signal(SIGPIPE, crashed);
  162.     if (setjmp(terminate) == 0)
  163.         transfer(conn);
  164.     close(conn);
  165.     if (debug)
  166.        fprintf(stderr, "\nNet connection closed: %d bytes written, %d read\n",
  167.                                                 byteswrote, bytesread);
  168.     exit(0);
  169. }
  170.  
  171. /*
  172.  * setup_socket
  173.  * Turn a hostname string and port into a sockaddr structure.
  174.  * Returns TRUE or FALSE.
  175.  */
  176.  
  177. int
  178. setup_socket(soc, host, port)
  179.     struct sockaddr_in *soc;
  180.     char *host;
  181.     unsigned short port;
  182. {
  183.     struct hostent *entry;
  184.  
  185.     soc->sin_family = AF_INET;
  186.     soc->sin_port = htons(port);
  187.     soc->sin_addr.s_addr = inet_addr(host);
  188.     if (soc->sin_addr.s_addr != -1)
  189.         return(TRUE);
  190.     entry = gethostbyname(host);
  191.     if (entry && entry->h_addr && (entry->h_addrtype == AF_INET)) {
  192.      bcopy(entry->h_addr,&soc->sin_addr.s_addr, entry->h_length);
  193. /*     strncpy(&soc->sin_addr.s_addr, entry->h_addr, entry->h_length); */
  194.         return(TRUE);
  195.     }
  196.     fprintf(stderr, "Unknown hostname or address - \"%s\"\n", host);
  197.     return(FALSE);
  198. }
  199.  
  200. /*
  201.  * crashed
  202.  * Come here if connection failed
  203.  */
  204.  
  205. void
  206. crashed()
  207. {
  208.     if (debug)
  209.         perror("tcpf lost connection");
  210.     longjmp(terminate, 1);
  211. }
  212.  
  213. /*
  214.  * setup_connection
  215.  * Open a TCP connection to the specified address
  216.  */
  217.  
  218. int
  219. setup_connection(soc)
  220.     struct sockaddr_in *soc;
  221. {
  222.     int conn;
  223.     int i;
  224.  
  225.     conn = socket(AF_INET, SOCK_STREAM, 0);
  226.     if (conn < 0) {
  227.         if (debug)
  228.             perror("socket");
  229.         return(-1);
  230.     }
  231.     if (openwait) {
  232.         for (i=0; i < openwaitlen; i++) {
  233.             if (connect(conn,soc, sizeof(*soc)) >= 0)
  234.                 break;
  235.             if (i==0 && debug) {
  236.                 fprintf(stderr,"Waiting... ");
  237.                 fflush(stderr);
  238.             }
  239.             sleep(1);
  240.             close(conn);
  241.             conn = socket(AF_INET, SOCK_STREAM, 0);
  242.             if (conn < 0) {
  243.                 if (debug)
  244.                     perror("socket");
  245.                 return(-1);
  246.             }
  247.         }
  248.         if (i >= openwaitlen) {
  249.             if (debug)
  250.                 perror("connect");
  251.             return(-1);
  252.         }
  253.     } else if (connect(conn, soc, sizeof(*soc)) < 0) {
  254.         if (debug)
  255.             perror("connect");
  256.         return(-1);
  257.     }
  258.     if (debug)
  259.         fprintf(stderr, "Open\n");
  260.     return(conn);
  261. }
  262.  
  263. /*
  264.  * transfer
  265.  * Write data from stdin to the specified connection.
  266.  * Read data from connection to stdout.
  267.  */
  268.  
  269. void
  270. transfer(net)
  271.     int net;
  272. {
  273.     int tib, nib, count;
  274.     unsigned char *tibptr, *nibptr, *stiptr, *stoptr;
  275.     int nready, readmask, writemask;
  276.     int stdinmask, stdoutmask, netinmask, netoutmask;
  277.     struct timeval timeout;
  278.     int neteof, stdeof, nonblock;
  279.  
  280.     bytesread = byteswrote = 0;
  281.     tib = nib = 0;
  282.     neteof = stdeof = FALSE;
  283.     stdinmask = (1 << fileno(stdin));
  284.     stdoutmask = (1 << fileno(stdout));
  285.     netinmask = (1 << net);
  286.     netoutmask = (1 << net);
  287.     timeout.tv_sec = timeoutlen;
  288.     timeout.tv_usec = 0;
  289.     nonblock = 1;
  290.     ioctl(net, FIONBIO, &nonblock);
  291.     setbuf(stdin, NULL);
  292.     setbuf(stdout, NULL);
  293.     while (TRUE) {
  294.         if ((tib == 0) && (nib == 0) && (neteof == TRUE) && (stdeof == TRUE))
  295.             return;
  296.         readmask = 0;
  297.     if (tib == 0)
  298.         readmask |= (stdeof ? 0 : stdinmask);
  299.     if (nib == 0)
  300.         readmask |= (neteof ? 0 : netinmask);
  301.         writemask = 0;
  302.         if (tib)
  303.            writemask |= netoutmask;
  304.         if (nib)
  305.            writemask |= stdoutmask;
  306.         nready = select(8*sizeof(int), &readmask, &writemask, NULL, 
  307.                         (timeoutmode ? &timeout : NULL));
  308.     if (debug)
  309.         printf("\nnready %d, rmask %4x, wmask %4x",
  310.            nready, readmask, writemask);
  311.         if (nready <= 0)
  312.             /* exit if timeout or eror */
  313.             return;
  314.  
  315.         /*
  316.          * First we try reading from the net
  317.          */
  318.         if ((nib == 0) && (readmask & netinmask) && (neteof == FALSE)) {
  319.             nibptr = netbuffer;
  320.             nib = read(net, nibptr, BUFSIZ);
  321.             if (debug)
  322.                 fprintf(stderr,"\nRead %d bytes from net", nib);
  323.             if ((nib == 0) || (nib == -1)) {
  324.                 nib = 0;
  325.                 neteof = TRUE;
  326.             }
  327.             else {
  328.                 bytesread += nib;
  329.                 if (eofmode && (netbuffer[nib-1] == '\004')) {
  330.                     netbuffer[--nib] = '\000';
  331.                     neteof = TRUE;
  332.                 }
  333.             }
  334.         }
  335.  
  336.         /*
  337.          * If we have input from the net, try writing it to standard out.
  338.          */
  339.         if ((nib > 0) && (writemask & stdoutmask)) {
  340.             count = write(fileno(stdout), nibptr, nib);
  341.             if (debug)
  342.                 fprintf(stderr,"\nWrote %d bytes to stdout", count);
  343.             if ((count == nib) || (count < 0))
  344.                 nib = 0;
  345.             else {
  346.                 nibptr += count;
  347.                 nib -= count;
  348.             }
  349.         }
  350.  
  351.         /*
  352.          * Now read from standard input.  If we read EOF and the user
  353.          * wants us to pass it through, send a CTRL/D.  This is very
  354.          * useful when dealing with PostScript printers that require
  355.          * the last character of a job be CTRL/D.
  356.          */
  357.         if ((tib == 0) && (readmask & stdinmask) && (stdeof == FALSE)) {
  358.             tibptr = ttybuffer;
  359.             tib = read(fileno(stdin), tibptr, BUFSIZ);
  360.             if (debug)
  361.                 fprintf(stderr,"\nRead %d bytes from stdin", tib);
  362.             if ((tib == 0) || (tib == -1)) {
  363.                 if ((tib == 0) && (eofmode == TRUE) && byteswrote) {
  364.                     if (debug)
  365.                         fprintf(stderr, " -- sending EOF character");
  366.                     tib = 1;
  367.                     ttybuffer[0] = '\004';
  368.                 }
  369.                 else
  370.                     tib = 0;
  371.                 stdeof = TRUE;
  372.             }
  373.             /*
  374.              * Convert <LF> to <CR><LF>. Preexisting <CR><LF> pairs not hurt,
  375.              * as <CR><CR><LF> has same effect. Uses this slow loop, rather
  376.              * than "memccpy", because the memory routines do not exist on
  377.              * all Unixes.
  378.              */
  379.             if (crlfmode) {
  380.                 for (stiptr = ttybuffer, stoptr = netoutbuffer;
  381.                      ((stiptr - ttybuffer) < tib);) {
  382.                     if (*stiptr == LF) {
  383.                         *stoptr++ = CR;
  384.                     }
  385.                     *stoptr++ = *stiptr++;
  386.                 }
  387.                 tib = (stoptr - netoutbuffer);
  388.                 tibptr = netoutbuffer;
  389.             }
  390.         }
  391.  
  392.         /*
  393.          * If we have input from standard input, try writing to the net
  394.          */
  395.         if ((tib > 0) && (writemask & netoutmask)) {
  396.             errno = 0;
  397.             count = write(net, tibptr, tib);
  398.             if (debug)
  399.                 fprintf(stderr,"\nWrote %d bytes to net", count);
  400.             if (count < 0) {
  401.                 if ((errno != ENOBUFS) && (errno != EWOULDBLOCK))
  402.                     longjmp(terminate, -1);
  403.                 count = 0;
  404.             }
  405.             byteswrote += count;
  406.             tibptr += count;
  407.             tib -= count;
  408.         }
  409.  
  410.         /*
  411.          * If we hit EOF on either side, maybe set EOF on other side.
  412.          */
  413.         if ((stdeof == TRUE) && ((readmask & netinmask) == 0)&&(!timeoutmode))
  414.             neteof = TRUE;
  415.         if ((neteof == TRUE) && ((readmask & stdinmask) == 0)&&(!timeoutmode))
  416.             stdeof = TRUE;
  417.     }
  418. }
  419.